package com.yupi.springbootinit.manager;

import com.yupi.springbootinit.common.ErrorCode;
import com.yupi.springbootinit.exception.BusinessException;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 专门提供 RedisLimiter 限流基础服务的（提供了通用的能力）
 */
@Service
public class RedisLimiterManager {

    @Resource
    private RedissonClient redissonClient;

    /**
     * 限流操作
     *
     * @param key 区分不同的限流器，比如不同的用户 id 应该分别统计
     */
    public void doRateLimit(String key) {
        // 创建一个名称为user_limiter的限流器，每秒最多访问 2 次，它接受一个参数 key，用于标识不同的限流器。
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
        /**
         * @Description: 设置限流器的速率。这里使用 trySetRate 方法，指定限流类型为 RateType.OVERALL，速率为每秒 2 次请求，并且速率的时间单位为秒。
         * 初始化RateLimiter的状态并将配置存储到Redis服务器。
         * 参数:
         * Mode——速率模式
         * Rate - - Rate
         * rateInterval -速率时间间隔
         * rateIntervalUnit -速率时间间隔单位
         * 返回: 如果设置了rate，则为True，否则为false
         */
        rateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);
        // 尝试请求一个令牌（即执行一个操作）。这里使用 tryAcquire 方法，请求一个令牌，参数 1 表示请求一个令牌。
        boolean canOp = rateLimiter.tryAcquire(1);
        // 如果请求令牌失败（即没有足够的可用令牌），则抛出一个自定义的业务异常，异常代码为 TOO_MANY_REQUEST，表示请求过多。
        if (!canOp) {
            throw new BusinessException(ErrorCode.TOO_MANY_REQUEST);
        }
    }
}
